package link.jfire.socket.socketserver.bus;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import link.jfire.baseutil.collection.ByteBufferPool;
import link.jfire.baseutil.simplelog.ConsoleLogFactory;
import link.jfire.baseutil.simplelog.Logger;
import link.jfire.socket.socketserver.storage.SingleProduceAndConsumerQueue;
import link.jfire.socket.socketserver.storage.WritePacket;
import link.jfire.socket.socketserver.transfer.handler.socket.ChannelReadHandler;
import link.jfire.socket.socketserver.transfer.handler.socket.MessageWriteHandler;
import link.jfire.socket.socketserver.transfer.server.ServerStatus;

@Resource(shareable = false)
public class ServerChannelInfo
{
    // 消息通道的打开状态
    private volatile Boolean                                 openStatus     = Boolean.TRUE;
    // 该线路是否被授权,默认上来都是未授权
    private volatile boolean                                 authentication = false;
    @Resource
    private ServerStatus                                     serverStatus;
    @Resource
    private ChannelReadHandler                               channelReadCompleteHandler;
    @Resource
    private MessageWriteHandler                              messageWriteCompleteHandler;
    // 消息自身持有的socket通道
    private AsynchronousSocketChannel                        socketChannel;
    // 通道中进行数据读入的buffer
    private ByteBuffer                                       readBuffer     = ByteBufferPool.getBuffer(1024);
    private static Logger                                    logger         = ConsoleLogFactory.getLogger();
    // 读取超时时间
    private long                                             readTimeout;
    // 最后一次读取时间
    private volatile long                                    lastReadTime;
    // 本次读取的截止时间
    private volatile long                                    endReadTime;
    // 启动读取超时的计数
    private volatile boolean                                 startCountdown = false;
    private long                                             waitTimeout;
    /** 通道持有对报文内容进行对称加解密的密钥 */
    private byte[]                                           key;
    private String                                           address;
    private final SingleProduceAndConsumerQueue<WritePacket> sendQueue      = new SingleProduceAndConsumerQueue<>();
    private Map<String, Object>                              contextMap;
    
    /**
     * 该消息线路是否已经被授权
     * 
     * @return
     */
    public boolean isAuthentication()
    {
        return authentication;
    }
    
    /**
     * 将消息线路设置为授权状态
     */
    public void authMsg()
    {
        authentication = true;
    }
    
    /**
     * 当前的socket通道是否打开
     * 
     * @return
     */
    public boolean isOpen()
    {
        return openStatus;
    }
    
    /**
     * 关闭链接。 该方法会将自身状态设置为关闭，关闭本身所拥有的socket链接，从服务器注册状态中删除自身，将自身所持有的buffer返还给缓存池
     */
    public void close()
    {
        if (openStatus == false)
        {
            return;
        }
        synchronized (openStatus)
        {
            if (openStatus)
            {
                openStatus = false;
            }
            else
            {
                return;
            }
        }
        try
        {
            socketChannel.close();
        }
        catch (IOException e)
        {
            logger.error("关闭通道异常", e);
        }
        serverStatus.remove(this);
        ByteBufferPool.returnBuffer(readBuffer);
    }
    
    public void setSocketChannel(AsynchronousSocketChannel socketChannel)
    {
        this.socketChannel = socketChannel;
        try
        {
            address = socketChannel.getRemoteAddress().toString();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    
    public ByteBuffer getReadBuffer()
    {
        return readBuffer;
    }
    
    public void setReadTimeout(long readTimeout)
    {
        this.readTimeout = readTimeout;
    }
    
    /**
     * 开始空闲读取等待，并且将倒数计时状态重置为false
     */
    public void startReadWait()
    {
        startCountdown = false;
        socketChannel.read(readBuffer, waitTimeout, TimeUnit.MILLISECONDS, this, channelReadCompleteHandler);
    }
    
    /**
     * 在通道上继续读取未读取完整的数据
     */
    public void continueRead()
    {
        if (startCountdown == false)
        {
            lastReadTime = System.currentTimeMillis();
            endReadTime = lastReadTime + readTimeout;
            startCountdown = true;
        }
        socketChannel.read(readBuffer, getRemainTime(), TimeUnit.MILLISECONDS, this, channelReadCompleteHandler);
        lastReadTime = System.currentTimeMillis();
    }
    
    /**
     * 剩余的读取消息时间
     * 
     * @return
     */
    public long getRemainTime()
    {
        return endReadTime - lastReadTime;
    }
    
    /**
     * 设置消息线路的等待时长
     * 
     * @param waitTimeout
     */
    public void setWaitTimeout(long waitTimeout)
    {
        this.waitTimeout = waitTimeout;
    }
    
    public AsynchronousSocketChannel getSocketChannel()
    {
        return socketChannel;
    }
    
    public String getAddress()
    {
        return address;
    }
    
    public MessageWriteHandler getMessageWriteCompleteHandler()
    {
        return messageWriteCompleteHandler;
    }
    
    public void setReadBuffer(ByteBuffer readBuffer)
    {
        this.readBuffer = readBuffer;
    }
    
    /**
     * 设置通道数据报文加解密使用的密钥
     * 
     * @param key
     */
    public void setKey(byte[] key)
    {
        this.key = key;
    }
    
    public byte[] getKey()
    {
        return key;
    }
    
    public boolean isTopWritePacket(WritePacket packet)
    {
        return sendQueue.isTop(packet);
        // return sendQueue.peek() == packet;
    }
    
    public void sendOne()
    {
        sendQueue.poll();
    }
    
    public WritePacket waitForSend()
    {
        return sendQueue.peek();
    }
    
    public void addWritePacket(WritePacket packet)
    {
        sendQueue.add(packet);
    }
    
    public int left()
    {
        return sendQueue.size();
    }
    
    public Map<String, Object> getContextMap()
    {
        return contextMap;
    }
    
    public void setContextMap(Map<String, Object> contextMap)
    {
        this.contextMap = contextMap;
    }
    
}
